/**
This file is part of javaee-patterns.

javaee-patterns is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

javaee-patterns is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.opensource.org/licenses/gpl-2.0.php>;.

 * Copyright (c) 22. June 2009 Adam Bien, blog.adam-bien.com
 * http://press.adam-bien.com
 */
package br.ucb.ProjetoFinal.util;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * A minimalistic implementation of the generic CrudService.
 * @author adam-bien.com
 */
@Stateless
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class CrudService {

    @PersistenceContext
    private EntityManager em;

    public void setEm(EntityManager em) {
        this.em = em;
    }
    
    private EntityManager getEm(){
        return em;
    }
    
    public <T> T create(T t) {
        getEm().persist(t);
        getEm().flush();
        getEm().refresh(t);
        return t;
    }

    @SuppressWarnings("unchecked")
    public <T> T find(Class<T> type, Object id) {
        return (T) getEm().find(type, id);
    }

    @SuppressWarnings("unchecked")
    public <T> List<T> findAll(Class<T> entityClass) {
        Query query = em.createQuery("select e from "
                + entityClass.getSimpleName() + " e");
        return query.getResultList();
    }

    public void delete(Class type, Object id) {
        Object ref = getEm().getReference(type, id);
        getEm().remove(ref);
    }

    public <T> T update(T t) {
        return (T) getEm().merge(t);
    }

    public List findWithNamedQuery(String namedQueryName) {
        return getEm().createNamedQuery(namedQueryName).getResultList();
    }

    public List findWithNamedQuery(String namedQueryName, Map<String, Object> parameters) {
        return findWithNamedQuery(namedQueryName, parameters, 0);
    }

    public List findWithNamedQuery(String queryName, int resultLimit) {
        return getEm().createNamedQuery(queryName).
                setMaxResults(resultLimit).
                getResultList();
    }

    public List findByNativeQuery(String sql, Class type) {
        return getEm().createNativeQuery(sql, type).getResultList();
    }

    public <T> T findSingleWithNamedQuery(String namedQueryName, Map<String, Object> parameters) {
        Set<Entry<String, Object>> rawParameters = parameters.entrySet();
        Query query = getEm().createNamedQuery(namedQueryName);

        for (Entry<String, Object> entry : rawParameters) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        try {
            return (T) query.getSingleResult();
        } catch (javax.persistence.NoResultException e) {
            return null;
        }
    }

    public List findWithNamedQuery(String namedQueryName, Map<String, Object> parameters, int resultLimit) {
        Set<Entry<String, Object>> rawParameters = parameters.entrySet();
        Query query = getEm().createNamedQuery(namedQueryName);
        if (resultLimit > 0) {
            query.setMaxResults(resultLimit);
        }
        for (Entry<String, Object> entry : rawParameters) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return query.getResultList();
    }
    
    public List findWithCustomQuery(String query, Map<String, Object> parameters) {
        return findWithCustomQuery(query, parameters, 0);
    }

    
    public List findWithCustomQuery(String query, Map<String, Object> parameters, int max) {
        Query qq = getEm().createQuery(query);
        setParameters(qq, parameters);
        return validateResultList(qq, max);
    }
    
    private void setParameters(Query qq, Map<String, Object> parameters){
        if (parameters!=null){
            for (String key : parameters.keySet()){
                qq.setParameter(key, parameters.get(key));
            }
        }
    }
    
    /** Valida o máximo permitido na busca e solta uma exceção caso o máximo seja excedido */
    private List validateResultList(Query query, int max){
        if (max>0){
            query.setMaxResults(max+1);
            List l = query.getResultList();
            if (l.size()>max){
//                throw new ServiceException("MaxResultadosExcedido");
                return l.subList(0, max);
            }else{
                return l;
            }
        }
        return query.getResultList();
    }
}
